package main

import (
	"fmt"
	"strconv"
	"strings"
)

// Node 是 AST 的抽象接口
type Node interface {
	Interpret(ctx *Context) float64
}

// Context 存储变量映射
type Context struct {
	vars map[string]float64
}

func NewContext() *Context {
	return &Context{vars: make(map[string]float64)}
}

// ValueNode 表示数字
type ValueNode struct {
	Value float64
}

func (n *ValueNode) Interpret(ctx *Context) float64 {
	return n.Value
}

// VariableNode 表示变量
type VariableNode struct {
	Name string
}

func (n *VariableNode) Interpret(ctx *Context) float64 {
	return ctx.vars[n.Name]
}

// BinaryNode 表示二元运算
type BinaryNode struct {
	Op    string
	Left  Node
	Right Node
}

func (n *BinaryNode) Interpret(ctx *Context) float64 {
	a := n.Left.Interpret(ctx)
	b := n.Right.Interpret(ctx)
	switch n.Op {
	case "+":
		return a + b
	case "-":
		return a - b
	case "*":
		return a * b
	case "/":
		return a / b
	default:
		panic("unknown op")
	}
}

// LetNode 表示 let 语句：let x = expr
type LetNode struct {
	Name  string
	Value Node
}

func (n *LetNode) Interpret(ctx *Context) float64 {
	v := n.Value.Interpret(ctx)
	ctx.vars[n.Name] = v
	return v
}

// 简化版 Parser，仅支持形式固定的表达式
func parseLet(s string) Node {
	// 支持: let x = expr
	parts := strings.SplitN(s, "=", 2)
	name := strings.TrimSpace(strings.TrimPrefix(parts[0], "let"))
	expr := parseExpr(strings.TrimSpace(parts[1]))
	return &LetNode{Name: name, Value: expr}
}

func parseExpr(s string) Node {
	// 这里只示范 form: a + b 或 a * b，不处理优先级和括号
	for _, op := range []string{"+", "-", "*", "/"} {
		if parts := strings.Split(s, op); len(parts) == 2 {
			return &BinaryNode{
				Op:    op,
				Left:  parseFactor(strings.TrimSpace(parts[0])),
				Right: parseFactor(strings.TrimSpace(parts[1])),
			}
		}
	}
	return parseFactor(s)
}

func parseFactor(s string) Node {
	if val, err := strconv.ParseFloat(s, 64); err == nil {
		return &ValueNode{Value: val}
	}
	return &VariableNode{Name: s}
}

func main() {
	ctx := NewContext()
	stmts := []string{
		"let x = 5",
		"let y = 2",
		"x + y * 3",
	}
	var last float64
	for _, line := range stmts {
		var node Node
		if strings.HasPrefix(line, "let ") {
			node = parseLet(line)
		} else {
			node = parseExpr(line)
		}
		last = node.Interpret(ctx)
		fmt.Println("=>", last)
	}
}
